/**
 * Created by juyong li on 2016/12/2.
 */
(function (window, angular) {
    'use strict';
    angular.module("Service.Security", [])
        .service("SecurityUtil", ["$q", "ybHttp","ybWidget", function ($q, ybHttp,ybWidget) {
            var _rsa = new RSAKey();
            var _key;
            var _iv;

            function _RefreshRsa() {
                var defer = $q.defer();
                ybHttp.Get("Security/RsaKey").then(function (data) {
                    if (data.Code != 0) {
                        ybWidget.ShowMessage(data);
                        return;
                    }
                    _rsa.setPublic(data.Value.Modulus, data.Value.Exponent);
                    defer.resolve();
                });
                return defer.promise;
            };
            function _RefreshAes() {
                var defer = $q.defer();
                var keyivs = _key + "|" + _iv;
                var cipher = cryptico.b16to64(_rsa.encrypt(keyivs));
                ybHttp.Post("security/updateAes", {Key: cipher}).then(function (data) {
                    if (data.Code != 0) {
                        ybWidget.ShowMessage(data);
                        return;
                    }
                    defer.resolve();
                });
                return defer.promise;
            };
            function _UpdateAes(){
                var defer = $q.defer();
                _RefreshRsa().then(function(){
                    _key=_randomKeyVi();
                    _iv=_randomKeyVi(16);
                    _RefreshAes().then(function(){
                        defer.resolve();
                    });
                });
                return defer.promise;
            };
            function  _AesEncrypt(plaintext) {
                if( !plaintext )
                {
                    return;
                }
                var byteIv = CryptoJS.enc.Utf8.parse(_iv);
                var byteKey = CryptoJS.enc.Utf8.parse(_key);
                var cfg = {mode:CryptoJS.mode.CBC,padding:CryptoJS.pad.Pkcs7,iv:byteIv};

                var enc=CryptoJS.AES.encrypt(plaintext,byteKey,cfg);
                return enc.toString();
            };
            function  _AesDecrypt(ciphertext) {
                if( !ciphertext){
                    return;
                }
                var byteIv = CryptoJS.enc.Utf8.parse(_iv);
                var byteKey = CryptoJS.enc.Utf8.parse(_key);
                var cfg = {mode:CryptoJS.mode.CBC,padding:CryptoJS.pad.Pkcs7,iv:byteIv};
                var dec = CryptoJS.AES.decrypt(ciphertext,byteKey,cfg);
                return CryptoJS.enc.Utf8.stringify(dec);
            };
            function _randomKeyVi(len) {
                len = len || 32;
                var $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
                var maxPos = $chars.length;
                var random = '';
                for (var i = 0; i < len; i++) {
                    random += $chars.charAt(Math.floor(Math.random() * maxPos));
                }
                return random;
            };
            function _HmacSha1Sign(text){
                var byteKey = CryptoJS.enc.Utf8.parse(_key);
                var enc=CryptoJS.HmacSHA1(text,byteKey);
                return CryptoJS.enc.Base64.stringify(enc);
            };
            function _CheckEnable(){
                if(_key){
                    return true;
                }
                return false;
            }
            return {
                RefreshRsa: _RefreshRsa,
                RefreshAes: _RefreshAes,
                UpdateAes: _UpdateAes,
                AesEncrypt:_AesEncrypt,
                AesDecrypt:_AesDecrypt,
                HmacSha1Sign:_HmacSha1Sign,
                CheckEnable:_CheckEnable
            }

        }])
        .service("EloanKey",['ybWidget',function(ybWidget){
        //+-------------------------------------------------------------------------
        //  Certificate Information Flags
        //--------------------------------------------------------------------------
        var CERT_INFO_ISSUER_FLAG                       =4;
        //+-------------------------------------------------------------------------
        // Certificate comparison functions
        //--------------------------------------------------------------------------
        var CERT_COMPARE_SHIFT          =16;
        var CERT_COMPARE_ANY            =0;
        var CERT_COMPARE_NAME_STR_W     =8;
        //+-------------------------------------------------------------------------
        //  dwFindType
        //
        //  The dwFindType definition consists of two components:
        //   - comparison function
        //   - certificate information flag
        //--------------------------------------------------------------------------
        var CERT_FIND_ANY           =(CERT_COMPARE_ANY << CERT_COMPARE_SHIFT);
        var CERT_FIND_ISSUER_STR_W  =(CERT_COMPARE_NAME_STR_W << CERT_COMPARE_SHIFT | CERT_INFO_ISSUER_FLAG);
        var CERT_FIND_ISSUER_STR	=CERT_FIND_ISSUER_STR_W;

        function _openStore()
        {
            try
            {
                Com11Store.Open("my");
            }
            catch(e)
            {}
        }
        function _findCertificates()
        {
            try
            {
                var objects = null;
                objects = Com11Store.FindCertificateInStore(
                    CERT_FIND_ISSUER_STR, AppData.config.eloanCertificate
                );
                if(null != objects)
                {
                    var objs = new VBArray( objects ).toArray();
                    var dnList = [];                   
                    for( var i=0; i<objs.length; i++ )
                    {
                        var tempString = objs[i].substring(2, objs[i].length);
                        dnList.push(tempString);
                    }
                    return dnList;
                }
            }
            catch(e)
            {
               // ybWidget.ShowMessage("")
                return ;
            }
        }

            /**
             * 取得连接在电脑上所有USB Key的介质数量
             * @returns {boolean}
             * @private
             */
        function _tokenInsertedValidation(){
            try{
                if (AbcCertFirm == "" || AbcCertFirm == null) {
                    while (parseInt(window.dialogArguments.parent.top.AbcCertFirm.getAllMediaIDCounts()) <= 0) {
                        alert("请您插入K宝！");
                        return false;
                    }
                } else {
                    while (parseInt(AbcCertFirm.getAllMediaIDCounts()) <= 0) {//判断
                        alert("请您插入K宝！");
                        return false;
                    }
                }
            }
            catch(e)
            {
                alert("请更新为最新的K宝驱动后重新操作，谢谢！");
                return false;
            }
            return true;
        }
         /**
          * * 签名函数，返回签名密文
          * @dn    DN信息
          * @GMZFlag  K宝国密标志 （0-非国密，1-国密）
          * @signId  签名控件的Id 目前设定的是AbcSign（<OBJECT id="AbcSign" style="WIDTH: 0px; HEIGHT:0px; position:absolute"
          classid="CLSID:A28A28DC-8AC5-442A-9BCD-7A2DB909AF5D" VIEWASTEXT></OBJECT>）
          * @SNType  K宝类型
          * @singName 签名信息名称
          * @oriData 签名原文
          **/
        function _makeSign(dn, GMZFlag, signId, SNType, singName,oriData){
            var tempsingcontrol_ = document.getElementById(signId);
             /**
              * 函数说明
              将业务数据组装成待签名报文。
              函数原型
              AddFormItem(String isshow, String index, String name, String value)
              参数说明：
              @isshow：是否在液晶key上显示，1’为显示，‘0’表示不显示；
              @index：业务数据编号；
              @name：业务数据名称；
              @value： 业务数据。
              调用示例：
              AddFormItem（'1','1',”转帐用户名：”,”李四”）；
              注意事项：
              业务数据和名称默认按照GBK方式编码，如果要改变编码，需要先用SetTextCode设置语言及编码。
              如果要添加签名文件，则必须全部添加完签名文件后再开始添加业务数据。
              *
              */
            tempsingcontrol_.addFormItem("1",0,singName,oriData);
            var singtext = '' ;
            if(GMZFlag == "1") {
                /**
                *函数说明
                 通过该接口调用，调用国密K宝的管理动态库的接口进行签名，签名结果附加原文。另外的接口AttachedSign是通过调用CSP的接口进行签名。
                 函数原型：
                 String GMAttachedSign(String dn， String hashAlg，String keyType, String signAlg)
                 参数说明：
                 @Dn，要进行签名的证书dn值，此处不能为空
                 @keyType：K宝类型，用于确认要调用的厂商动态库
                 @signAlg：签名算法，指定是rsa证书还是sm2证书，参数值可以为“RSA”、“SM2”
                 @hashAlg：hash算法，若此处为空，使用默认的hash算法，rsa证书为sha1，SM2证书为SM3。Hash算法可以取值为“SHA1”、“SHA256”、“SHA384”、“SHA512”、“SM3”。
                 调用示例：
                 GMAttachedSign("CN=123"，"SM3","43","SM2")
                *
                 */
                singtext = tempsingcontrol_.GMAttachedSign(dn,"",SNType,"sm2");
            }else {
                /**
                *函数说明
                 根据证书DN在系统中查找证书，若参数中输入的dn为空，则需要调用csp枚举注册到系统中的证书，选择证书调用csp对添加的TLV报文进行Attach签名。
                 函数原型：
                 String AttachedSign(String dn)
                 参数说明：
                 @dn：要进行签名的证书DN值
                 调用示例：
                 AttachedSig("CN=test123")
                 */
                singtext = tempsingcontrol_.AttachedSign(dn);
            }
            return singtext;
        };
        return {
            OpenStore: _openStore,
            FindCertificates: _findCertificates,
            TokenInsertedValidation: _tokenInsertedValidation,
            MakeSign:_makeSign
        };
    }])
})(window, window.angular);